// app/app.go
package app

import (
	"context"
	"errors"
	"fmt"
	"keGuanJia/app/routes"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/gin-gonic/gin"
	"keGuanJia/app/config"
)

const (
	DevelopmentMode = "dev"
	TestMode        = "test"
	LocalMode       = "local"
	ProductionMode  = "prod"
)

// 定义默认超时时间（单位：秒）
const (
	defaultReadTimeout  = 5
	defaultWriteTimeout = 10
	defaultIdleTimeout  = 120
)

const (
	// 定义默认端口
	defaultPort = "8080"
)

// Application 是应用核心结构
type Application struct {
	cfg config.Configuration // 应用配置
}

// New 创建 Application 实例并加载配置
func New() (*Application, error) {
	fmt.Println("🔧 Initializing application...")

	// 1. 加载配置
	cfg, err := config.LoadConfiguration()
	if err != nil {
		return nil, fmt.Errorf("failed to load configuration: %w", err)
	}

	// 2. 创建应用实例
	app := &Application{
		cfg: cfg,
	}

	// 3. 打印配置（调试用，生产建议用 zap/logrus）
	fmt.Printf("✅ Application config loaded: %+v\n", app.cfg)

	return app, nil
}

// Run 启动应用主流程：启动 HTTP 服务，监听端口，支持优雅关闭
func (a *Application) Run() error {
	fmt.Println("🚀 Starting HTTP server...")

	// 1. 创建 Gin 实例（生产环境建议使用 gin.SetMode(gin.ReleaseMode)）
	router := gin.Default()
	if a.cfg.Server.Env == ProductionMode {
		gin.SetMode(gin.ReleaseMode)

	}
	// 2. 注册路由
	// 🚀 关键：调用统一路由注册方法，自动注册所有模块的路由
	routes.SetupRoutes(router)

	// 3. 读取超时、写超时、空闲超时
	// 从配置中读取，如果为 0 则使用默认值
	readTimeout := a.cfg.Server.ReadTimeout
	if readTimeout == 0 {
		readTimeout = defaultReadTimeout
	}

	writeTimeout := a.cfg.Server.WriteTimeout
	if writeTimeout == 0 {
		writeTimeout = defaultWriteTimeout
	}

	idleTimeout := a.cfg.Server.IdleTimeout
	if idleTimeout == 0 {
		idleTimeout = defaultIdleTimeout
	}
	// 4. 创建 HTTP Server
	// 构造 http.Server，使用配置或默认超时
	srv := &http.Server{
		Handler:      router.Handler(),
		ReadTimeout:  time.Duration(readTimeout) * time.Second,
		WriteTimeout: time.Duration(writeTimeout) * time.Second,
		IdleTimeout:  time.Duration(idleTimeout) * time.Second,
	}

	// 5. 启动服务（封装函数）（非阻塞）
	port := a.cfg.Server.Port
	_, actualPort, err := startHTTPServer(srv, port)
	if err != nil {
		return fmt.Errorf("failed to start server: %w", err)
	}

	fmt.Printf("🚀 Server starting on :%d with timeouts - Read: %ds, Write: %ds, Idle: %ds \n",
		actualPort,
		readTimeout,
		writeTimeout,
		idleTimeout,
	)

	// 6. 用于优雅关闭的 channel
	done := make(chan os.Signal, 1)
	signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)

	// 7. 等待中断信号
	<-done
	fmt.Println("\n🛑 Received shutdown signal, gracefully stopping server...")

	// 8. 创建超时上下文，最多等待 5 秒
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	// 9. 优雅关闭 HTTP Server
	if err := srv.Shutdown(ctx); err != nil {
		fmt.Printf("⚠️ HTTP server shutdown error: %v\n", err)
	} else {
		fmt.Println("✅ HTTP server stopped gracefully")
	}

	return nil
}

// startHTTPServer 启动 HTTP 服务，支持自定义端口或随机端口，返回实际监听的 net.Listener
// 参数：
//   - srv: 已配置好的 *http.Server（包含 Handler、超时等配置）
//   - port: 用户配置的端口，比如 "8080" 或 ""（未配置，将使用随机端口）
//
// 返回值：
//   - net.Listener: 实际的监听器，可用于优雅关闭或获取端口
//   - int: 实际监听的端口，如果是随机端口则有意义，否则就是配置的端口
//   - error: 如果监听失败，返回错误
func startHTTPServer(srv *http.Server, port string) (net.Listener, int, error) {
	var addr string
	if port == "" {
		addr = ":0" // 随机端口
		fmt.Println("📡 Server port not configured, using random available port...")
	} else {
		addr = ":" + port
		fmt.Printf("📡 Server is configured to listen on port: %s \n", addr)
	}

	// 1. 手动监听 TCP 端口
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		return nil, 0, fmt.Errorf("failed to listen on %s: %w \n", addr, err)
	}

	// 2. 获取实际监听的地址（用于日志和随机端口）
	actualAddr := listener.Addr()
	var actualPort int

	if tcpAddr, ok := actualAddr.(*net.TCPAddr); ok {
		actualPort = tcpAddr.Port
		fmt.Printf("✅ Server is running on port: localhost:%d \n", actualPort)
	} else {
		// 理论上不应该走到这里，除非你监听的不是 TCP
		actualPort = 0
		fmt.Printf("⚠️ Server is running on non-TCP listener: %v \n", actualAddr)
	}

	// 3. 启动服务（非阻塞，使用 Serve 而不是 ListenAndServe）
	go func() {
		if err := srv.Serve(listener); err != nil && !errors.Is(err, http.ErrServerClosed) {
			log.Fatalf("❌ HTTP server error: %v", err)
		}
	}()

	return listener, actualPort, nil
}
